home *** CD-ROM | disk | FTP | other *** search
/ Network CD 2 / Network CD - Volume 2.iso / programs / internet / tcp / amitcp / amitcp-src-22.lha / AmiTCP-2.2 / src / devs / agnet / agnet.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-07  |  21.5 KB  |  889 lines

  1. RCS_ID_C="$Id: agnet.c,v 3.1 93/10/07 19:24:08 ppessi Exp $";
  2. /*
  3.  * agnet.c --- agnet main program and arexx interface
  4.  *
  5.  * Author: ppessi <Pekka.Pessi@hut.fi>
  6.  *
  7.  * Copyright (c) 1993 OHT-AmiTCP/IP Group,
  8.  *                    Helsinki University of Technology, Finland.
  9.  *                    All rights reserved.
  10.  *
  11.  * Created      : Sat Feb 20 18:30:59 1993 ppessi
  12.  * Last modified: Thu Oct  7 18:23:33 1993 ppessi
  13.  *
  14.  * $Log:    agnet.c,v $
  15.  * Revision 3.1  93/10/07  19:24:08  ppessi
  16.  * Release 2.1 version
  17.  * 
  18.  * Revision 2.1  93/05/14  16:46:32  ppessi
  19.  * Release version.
  20.  * 
  21.  * Revision 2.0  93/03/10  16:35:03 16:35:03  ppessi (Pekka Pessi)
  22.  * Prototype release.
  23.  */
  24.  
  25. #include <string.h>
  26. #include <stdarg.h>
  27.  
  28. #include <dos/dostags.h>
  29. #include <dos/rdargs.h>
  30. #include <intuition/intuition.h>
  31. #include <rexx/storage.h>
  32. #include <rexx/rxslib.h>
  33.  
  34. #include <clib/exec_protos.h>
  35. #include <clib/dos_protos.h>
  36. #include <clib/utility_protos.h>
  37. #include <clib/intuition_protos.h>
  38.  
  39. #ifdef __SASC
  40. #include <pragmas/exec_sysbase_pragmas.h>
  41. #include <pragmas/dos_pragmas.h>
  42. #include <pragmas/utility_pragmas.h>
  43. #include <pragmas/intuition_pragmas.h>
  44. #endif
  45.  
  46. #include "agnet.h"
  47. #include "agnet_protos.h"
  48. #include "agnet_rev.h"
  49. #include "bases.h"
  50.  
  51. static ULONG init_arexx(VOID);
  52. static VOID poll_arexx(VOID);
  53. static VOID deinit_arexx(VOID);
  54.  
  55. /*
  56.  * We start as a CLI.
  57.  * Assembler stub routine does a MakeLibrary and
  58.  * initializes needed librarybases
  59.  */
  60. LONG ASM main(REG(a6)struct AgnetDevice *adb)
  61. {
  62.   struct Process *proc;
  63.   struct IOSana2Req *io;
  64.   ULONG waitmask, rexxsignal, signals;
  65.   UBYTE devsignal;
  66.   UBYTE myname[sizeof(AGNETDEVNAME)+5];
  67.  
  68.   AgnetDeviceBase = adb;
  69.  
  70.   proc = (struct Process *)FindTask(0L);
  71.  
  72.   /* Initialize the device base */
  73.   adb->ad_Device.lib_Node.ln_Pri  = AGNET_DEV_PRI;
  74.   adb->ad_Device.lib_Node.ln_Type = NT_DEVICE;
  75.   adb->ad_Device.lib_Node.ln_Name = myname;
  76.   adb->ad_Device.lib_Version  = VERSION;
  77.   adb->ad_Device.lib_Revision = REVISION;
  78.   adb->ad_Device.lib_IdString = VSTRING;
  79.   adb->ad_Task = (struct Task *)proc;
  80.  
  81.   /* Set up our unit message port */
  82.   /* Attempt to allocate a signal bit for our Unit MsgPort. */
  83.   devsignal = AllocSignal(-1L);
  84.   if (devsignal == -1) {
  85.     return 20;
  86.   }
  87.   NewList(&adb->ad_MsgPort.mp_MsgList);
  88.   adb->ad_MsgPort.mp_SigBit = devsignal;
  89.   adb->ad_MsgPort.mp_SigTask = (struct Task *)proc;
  90.   adb->ad_MsgPort.mp_Flags = PA_SIGNAL;
  91.  
  92.   /* Initialize our device base semafore */
  93.   InitSemaphore(&adb->ad_Lock);
  94.  
  95.   InitLRandom();
  96.  
  97. #ifdef AGREXX
  98.   /* Initialize Arexx port */
  99.   rexxsignal = init_arexx();
  100. #else
  101.   rexxsignal = 0;
  102. #endif
  103.   /* OK, we are ready to add agnet.device to system */
  104.   {
  105.     int i, n = sizeof(AGNETDEVNAME) - 1;
  106.     strcpy(myname, AGNETDEVNAME);
  107.  
  108.     Forbid();
  109.     for (i = 0; i < 9; i++) {
  110.       if (!FindName(&adb->ad_SysBase->DeviceList, myname))
  111.     break;
  112.       myname[n] = '.'; myname[n+1] = '1' + i; myname[n+2] = '\0';
  113.     }
  114.     AddDevice(adb);
  115.     Permit();
  116.   }
  117.  
  118.   waitmask = (1<<devsignal) | rexxsignal | SIGBREAKF_CTRL_F ;
  119.  
  120.   while (TRUE) {
  121.     signals = Wait(waitmask);    /* wait for device command */
  122.  
  123.     if (signals & SIGBREAKF_CTRL_F) {
  124.       if (DoExpunge(adb))
  125.     break;
  126.     }
  127.  
  128.     while (io = (struct IOSana2Req *)GetMsg(&adb->ad_MsgPort)) 
  129.       PerformIO(io);
  130.  
  131. #ifdef AGREXX
  132.     if (signals & rexxsignal)
  133.       poll_arexx();
  134. #endif
  135.   }
  136.  
  137.   /* Clean up */
  138. #ifdef AGREXX
  139.   deinit_arexx();
  140. #endif
  141.   FreeSignal(devsignal);
  142.   return 0;
  143. }
  144.  
  145. /* Local prototypes */
  146. static LONG ParseConfig(struct AgnetDevUnit *, struct RDArgs *, STRPTR*);
  147. static BOOL GetBitAddress(UBYTE *addr, UBYTE *string, LONG bitsize);
  148. static char *SanaSprintf(register char *ap, int len);
  149. static ULONG csprintf(struct CSource *buf, const char *fmt, ...);
  150.  
  151. #define CONFIG_ENV_TEMPLATE "ENV:SANA2/config%ld.agnet"
  152.  
  153. #define UNINITIALIZED 0xffffffff
  154.  
  155. /*
  156.  *  ReadConfig
  157.  *
  158.  *  Attempt to read in the driver's configuration file.
  159.  *
  160.  *  The files are named by ENV:SANA2/agnet%d.config where %d is the decimal
  161.  *  representation of the device's unit number.
  162.  *
  163.  *  Return FALSE upon error.
  164.  */
  165. BOOL ReadConfig(struct AgnetDevUnit *adu)
  166. {
  167.   UBYTE *fbuf = NULL;
  168.   UBYTE buff[40];
  169.   struct CSource csbuff = { NULL, sizeof(buff), 0L };
  170.   BPTR ConfigFile;
  171.   LONG offset, len;
  172.   BOOL ok = FALSE;
  173.  
  174.   csbuff.CS_Buffer = buff;
  175.  
  176.   /* This configures unit by default values */
  177.   adu->adu_HardwareType = UNINITIALIZED;
  178.  
  179.   /* Create the name of our config file.. */
  180.   csprintf(&csbuff, CONFIG_ENV_TEMPLATE, (ULONG)adu->adu_UnitNum);
  181.  
  182.   /* ...and open it. */
  183.   ConfigFile = Open(buff, MODE_OLDFILE);
  184.   if (!ConfigFile) 
  185.     return TRUE;
  186.  
  187.   len = (Seek(ConfigFile, 0L, 1), Seek(ConfigFile, 0L, 0));
  188.   if (len >= 0 && (fbuf = AllocMem(len+2, MEMF_PUBLIC))) {
  189.     Seek(ConfigFile, 0L, -1);
  190.     if (Read(ConfigFile, fbuf, len) == len) {
  191.       ok = TRUE;
  192.       fbuf[len] = '\n';
  193.       fbuf[len+1] = '\0';
  194.     } 
  195.   }
  196.   Close(ConfigFile);
  197.  
  198.   if (ok) { 
  199.     struct RDArgs *rdargs = AllocDosObject(DOS_RDARGS, NULL);
  200.     STRPTR *errmsg;
  201.  
  202.     if (rdargs) {
  203.       /* Remove Comment lines */ 
  204.       for (offset = 0; offset < len;) {
  205.     if (fbuf[offset] == '#')
  206.       while(fbuf[offset] != '\n')
  207.         fbuf[offset++] = ' ';
  208.     else
  209.       while(fbuf[offset++] != '\n');
  210.     fbuf[offset - 1] = ' '; /* remove linefeeds in file */
  211.       }
  212.       /* Add sentinel */
  213.       fbuf[len] = '\n';
  214.  
  215.       rdargs->RDA_Source.CS_Buffer = fbuf;
  216.       rdargs->RDA_Source.CS_Length = len + 1;
  217.       rdargs->RDA_Source.CS_CurChr = 0;
  218.  
  219.       if (ParseConfig(adu, rdargs, &errmsg)) {
  220.     struct EasyStruct es;
  221.     APTR args[2];
  222.     args[0] = errmsg;
  223.     args[1] = buff;
  224.     es.es_StructSize = sizeof(es);
  225.     es.es_Flags = 0;
  226.     es.es_Title = AGNETDEVNAME;
  227.     es.es_TextFormat="Error %s in \nthe configuration file\n%s";
  228.     es.es_GadgetFormat="Okay";
  229.     EasyRequestArgs(NULL, &es, 0, args);
  230.     ok = FALSE;
  231.       }
  232.     }
  233.     FreeDosObject(DOS_RDARGS, rdargs);
  234.   }
  235.  
  236.   if (fbuf) FreeMem(fbuf, len+2);
  237.   return ok;
  238. }
  239.  
  240. #define MYREXXNAME "agnet"
  241. #define MYREXXEXTENSION "agnet"
  242.  
  243. /* Error strings */
  244. #define ERR_MALFORMED "Malformed command line"
  245. #define ERR_SYNTAX    "Syntax error"
  246. #define ERR_WIRE      "Illegal wiretype"
  247. #define ERR_ADDRESS   "Illegal address"
  248. #define ERR_UNIT      "Illegal unit number"
  249. #define ERR_INITUNIT  "Error initializing unit"
  250. #define ERR_MEMORY    "Memory exhausted"
  251. #define ERR_OPEN      "Unit is currently opened"
  252. #define ERR_VALUE     "Illegal value"
  253.  
  254. #ifdef AGREXX
  255. /*
  256.  * Arexx interface functions to agnet.device 
  257.  */
  258.  
  259. #include    <rexx/storage.h>
  260. #include    <rexx/rxslib.h>
  261. #include        <clib/rexxsyslib_protos.h>
  262. #ifdef __SASC
  263. #include    <pragmas/rexxsyslib_pragmas.h>
  264. #endif
  265. #include    "SimpleRexx.h"
  266.  
  267. AREXXCONTEXT    RexxContext;
  268.  
  269. static LONG ParseRexx(UBYTE *arg, UBYTE **errstr, UBYTE **result);
  270. static LONG ParseQuery(struct AgnetDevUnit *, struct RDArgs *,
  271.                STRPTR *,STRPTR *);
  272. /*
  273.  * Initialize Arexx port
  274.  */
  275. static ULONG 
  276. init_arexx(VOID)
  277. {
  278.   ULONG rexxsignal;
  279.  
  280.   RexxContext = InitARexx(MYREXXNAME, MYREXXEXTENSION);
  281.  
  282.   if (!RexxContext)
  283.     return 0L;
  284.  
  285.   rexxsignal = ARexxSignal(RexxContext);
  286.  
  287.   return rexxsignal;
  288. }
  289.  
  290. /* 
  291.  * Free ARexx port
  292.  */
  293. static VOID 
  294. deinit_arexx(VOID)
  295. {
  296.   if (RexxContext)
  297.     FreeARexx(RexxContext);
  298. }
  299.  
  300. /* 
  301.  * Poll Arexx port
  302.  */
  303. static VOID 
  304. poll_arexx(VOID)
  305. {
  306.   struct RexxMsg *rmsg;
  307.  
  308.   /*
  309.    * Process the ARexx messages...
  310.    */
  311.   while (rmsg = GetARexxMsg(RexxContext)) {
  312.     UBYTE *error = NULL, *result = NULL;
  313.     LONG errlevel=0;
  314.  
  315.     if (errlevel = ParseRexx(ARG0(rmsg), &error, &result)) {
  316.       SetARexxLastError(RexxContext, rmsg, error);
  317.     }
  318.     ReplyARexxMsg(RexxContext, rmsg, result, errlevel);
  319.   }
  320. }
  321.  
  322. /*
  323.  * Rexx commands
  324.  */
  325.  
  326. #define REXXKEYWORDS "U=UNIT,Q=QUERY,E=EXIT=EXPUNGE"
  327. #define KEYWORDLEN  16
  328.  
  329. #define KEY_UNIT 0
  330. #define KEY_QUERY 1
  331. #define KEY_EXIT 2
  332.  
  333. /*
  334.  * Parse the ARexx command 
  335.  */
  336. static LONG
  337. ParseRexx(UBYTE *arg, UBYTE **errstr, UBYTE **result)
  338. {
  339.   struct AgnetDevice *adb = AgnetDeviceBase;
  340.   LONG errlevel = 0;
  341.   UBYTE Buffer[KEYWORDLEN];
  342.   LONG len = LengthArgstring(arg) + 2;
  343.   UBYTE *cmd = AllocMem(len, 0);
  344.   struct RDArgs *rdargs = AllocDosObject(DOS_RDARGS, NULL);
  345.   LONG unit, keyword;
  346.   struct AgnetDevUnit *adu;
  347.  
  348.   if (!cmd || !rdargs) {
  349.     errlevel = 40;
  350.     *errstr = ERR_MEMORY;
  351.   } else {
  352.     memcpy(cmd, arg, len - 2);
  353.     /* Add sentinel */
  354.     cmd[len-2] = '\n'; cmd[len-1] = '\0';
  355.     rdargs->RDA_Source.CS_Buffer = cmd;
  356.     rdargs->RDA_Source.CS_Length = len - 1;
  357.     rdargs->RDA_Source.CS_CurChr = 0;
  358.     /* First, parse the command keyword */
  359.     if (ReadItem(Buffer, sizeof(Buffer), &rdargs->RDA_Source) <= 0 ||
  360.     (keyword = FindArg(REXXKEYWORDS, Buffer)) < 0) {
  361.       errlevel = 20;
  362.       *errstr = ERR_MALFORMED;
  363.     } else {
  364.       switch (keyword) {
  365.       case KEY_UNIT:
  366.       case KEY_QUERY:
  367.     /* Parse unit number */
  368.     if ((len = StrToLong(cmd + rdargs->RDA_Source.CS_CurChr, &unit)) < 0 ||
  369.         unit >= AD_MAXUNITS) {
  370.       errlevel = 20;
  371.       *errstr = ERR_UNIT;
  372.       break;
  373.     }
  374.     rdargs->RDA_Source.CS_CurChr += len;
  375.  
  376.     if (!(adu = adb->ad_Units[unit])) 
  377.       /* If there is no opened unit, we init one */
  378.       if (keyword == KEY_QUERY || !(adu = InitUnit(unit))) {
  379.         /* We got no unit structure, there was an initialization
  380.            problem, we must give up */
  381.         *errstr = ERR_INITUNIT;
  382.         errlevel = 20;
  383.         break;
  384.       }
  385.     if (keyword == KEY_UNIT) {
  386.       /* Parse the rest of the line with ParseConfig */
  387.       errlevel = ParseConfig(adu, rdargs, errstr);
  388.       break;
  389.     } else {
  390.       errlevel = ParseQuery(adb->ad_Units[unit], rdargs, errstr, result);
  391.       break;
  392.     }
  393.       case KEY_EXIT:
  394.     /* We try to expunge */
  395.     SetSignal(SIGBREAKF_CTRL_F, SIGBREAKF_CTRL_F);
  396.     break;
  397.       }
  398.     } 
  399.   } 
  400.     
  401.   if (cmd) FreeMem(cmd, len);
  402.   if (rdargs) FreeDosObject(DOS_RDARGS, rdargs);
  403.  
  404.   return errlevel;
  405. }
  406. #endif /* AGREXX */
  407.  
  408. /* 
  409.  * Configuration parameters
  410.  */
  411. #define CONFIG_ARGS              20    /* # of args in CONFIG_TEMPLATE */
  412. #define CONFIG_TEMPLATE "WIRE/K" \
  413.   ",MTU/N/K,MINTU/N/K,BPS/N/K,ADDR=ADDRESS/K" \
  414.   ",DELAY/N/K,DEV=DEVIATION/N/K,ERRORS/K/N,LOSS/K/N,DST=DSTUNIT/N"
  415.  
  416. #define CMD_WIRE      0
  417. #define CMD_MTU       1    /* Maximum transfer unit */
  418. #define CMD_MINTU     2    /* Minimum Trransfer unit */
  419. #define CMD_BPS       3    /* Bits per second */
  420. #define CMD_ADDR      4    /* Address string */
  421. #define CMD_DELAY     5    /* Delay in ms */
  422. #define CMD_DEVIATION 6    /* Deviation in ms */
  423. #define CMD_ERRORS    7 /* Bit error probability */
  424. #define CMD_LOSS      8    /* Packet loss probability */
  425. #define CMD_PPUNIT    9    /* Destination unit */
  426.  
  427. #define CMD_ALL      10 /* All values queried */
  428.                
  429. #define WIRE_TEMPLATE   "LOOPBACK,ETHERNET,IEEE802,ARCNET" \
  430.   ",LOCALTALK,AMOKNET" \
  431.   ",PPP,SLIP,CSLIP" \
  432.  
  433. #define WIRE_LOOPBACK  0
  434. #define WIRE_ETHERNET  1
  435. #define WIRE_IEEE802   2
  436. #define WIRE_ARCNET    3
  437. #define WIRE_LOCALTALK 4
  438. #define WIRE_AMOKNET   5
  439. #define WIRE_PPP       6
  440. #define WIRE_SLIP      7
  441. #define WIRE_CSLIP     8
  442.  
  443. #ifdef AGREXX
  444. #include <exec/initializers.h>
  445.  
  446. #define MAXQUERYLEN 512
  447.  
  448. #define QUERY_TEMPLATE "WIRE/S" \
  449.   ",MTU/S,MINTU/S,BPS/S,ADDR=ADDRESS/S" \
  450.   ",DELAY/S,DEV=DEVIATION/S,ERRORS/S,LOSS/S,DST=DSTUNIT/S,ALL/S"
  451.  
  452. static struct {
  453.   STRPTR title;
  454.   WORD offset;
  455.   enum { nulong, wire, address } type;
  456. } query_titles[] = {
  457.   { "WIRE",     OFFSET(AgnetDevUnit, adu_HardwareType), wire },
  458.   { "MTU",      OFFSET(AgnetDevUnit, adu_MaxTU),        nulong },
  459.   { "MINTU",    OFFSET(AgnetDevUnit, adu_MinTU),        nulong },
  460.   { "BPS",      OFFSET(AgnetDevUnit, adu_BPS),          nulong },
  461.   { "ADDRESS",  OFFSET(AgnetDevUnit, adu_Addr),         address },
  462.   { "DELAY",    OFFSET(AgnetDevUnit, adu_Delay),        nulong },
  463.   { "DEVIATION",OFFSET(AgnetDevUnit, adu_Deviation),    nulong },
  464.   { "ERRORS",   OFFSET(AgnetDevUnit, adu_Errors),       nulong },
  465.   { "LOSS",     OFFSET(AgnetDevUnit, adu_Loss),         nulong },
  466.   { "DSTUNIT",  OFFSET(AgnetDevUnit, adu_PPUnit),       nulong }
  467. };
  468.  
  469. #define AT_OFFSET(X,Y) ((UBYTE *)X + Y)
  470. #define ULONG_AT(X,Y) (*(ULONG*)AT_OFFSET(X,Y))
  471.  
  472. static struct {
  473.   ULONG  type;
  474.   STRPTR name;
  475. } wirenames[] = {
  476.   { S2WireType_LoopBack,  "Loopback" },
  477.   { S2WireType_Ethernet,  "Ethernet" },
  478.   { S2WireType_IEEE802,   "IEEE802" },
  479.   { S2WireType_Arcnet,    "Arcnet" },
  480.   { S2WireType_LocalTalk, "LocalTalk" },
  481.   { S2WireType_AmokNet,   "AmokNet" },
  482.   { S2WireType_PPP,       "PPP" },
  483.   { S2WireType_SLIP,      "SLIP" },
  484.   { S2WireType_CSLIP,     "CSLIP" },
  485.   { S2WireType_LoopBack,  "Unknown" }
  486. };
  487. #endif
  488.  
  489. /*
  490.  * Parse a configuration command
  491.  * adu = NULL if parse an ARexx command
  492.  * return differs from zero if an error
  493.  */
  494. static LONG 
  495. ParseConfig(struct AgnetDevUnit *adu, struct RDArgs *rdargs, 
  496.         STRPTR *errormessage)
  497. {
  498.   LONG args[CONFIG_ARGS] = {0};
  499.   LONG error; 
  500.   LONG ppunit;
  501.   UBYTE address[MAX_ADDR_BYTES] = {0};
  502.   UWORD addrfieldsize;
  503.   ULONG hardwaretype, maxtu, mintu, bps, delay, deviation, errors, loss;
  504.   BOOL virgin;
  505.   LONG wire;
  506.  
  507.   /* Parse the file or the line...*/
  508.   rdargs = ReadArgs(CONFIG_TEMPLATE, args, rdargs);
  509.   if (error = !rdargs) {
  510.     if (errormessage)
  511.       *errormessage = ERR_SYNTAX;
  512.     return error;
  513.   }
  514.  
  515.   hardwaretype = adu->adu_HardwareType;
  516.   addrfieldsize = adu->adu_AddrFieldSize;
  517.   ppunit = adu->adu_PPUnit;
  518.   maxtu = adu->adu_MaxTU;
  519.   mintu = adu->adu_MinTU;
  520.   bps   = adu->adu_BPS;
  521.   delay = adu->adu_Delay;
  522.   deviation = adu->adu_Deviation;
  523.   errors    = adu->adu_Errors;
  524.   loss      = adu->adu_Loss ;
  525.   memcpy(address, adu->adu_Addr, MAX_ADDR_BYTES);
  526.  
  527.   virgin = hardwaretype == UNINITIALIZED;
  528.  
  529.   if (args[CMD_WIRE]) {
  530.     wire = FindArg(WIRE_TEMPLATE, args[CMD_WIRE]);
  531.   } else if (virgin) {
  532.     wire = S2WireType_Ethernet;
  533.   }
  534.  
  535.   if (args[CMD_WIRE] || virgin) {
  536.     switch (wire) {
  537.     case WIRE_LOOPBACK:
  538.       /* This is simple loopback type */
  539.       hardwaretype = S2WireType_LoopBack;
  540.       addrfieldsize = 0;    /* No addresses */
  541.       maxtu = 1024;
  542.       bps   = 100000000;    /* it's fast like a hell...*/
  543.       mintu = 0;
  544.       /* There is no need for address but we zero it anyways */
  545.       memset(address, 0, MAX_ADDR_BYTES);
  546.       break;
  547.  
  548.     case WIRE_ETHERNET:
  549.       /* This is default */
  550.       hardwaretype = S2WireType_Ethernet;
  551.       addrfieldsize = 48;
  552.       maxtu = 1500;
  553.       bps   = 10000000;        /* 10 Mb/s */
  554.       mintu = 1;
  555.       /* Ethernet address is same as unit number */
  556.       memset(address + 6, 0, MAX_ADDR_BYTES-2);
  557.       memcpy(address, "ETHER", 5);
  558.       address[5] = adu->adu_UnitNum;
  559.       ppunit = -1;
  560.       break;
  561.  
  562.     case WIRE_IEEE802:
  563.       /* Wiretype is IEEE802 */
  564.       hardwaretype  = S2WireType_IEEE802;
  565.       addrfieldsize = 48;
  566.       maxtu = 1500;
  567.       bps   = 10000000;        /* 10 Mb/s */
  568.       mintu = 1;
  569.       /* IEEE802 address is same as unit number */
  570.       memset(address+6, 0, MAX_ADDR_BYTES-6);
  571.       memcpy(address, "IEEE8", 5);
  572.       address[5] = adu->adu_UnitNum;
  573.       ppunit = -1;
  574.       break;
  575.  
  576.     case WIRE_ARCNET:
  577.       hardwaretype  = S2WireType_Arcnet;
  578.       addrfieldsize = 8;
  579.       maxtu = 506;
  580.       bps   = 5000000L;        /* 5 Mb/s */
  581.       mintu = 1;
  582.       /* Arcnet address is got from unit number */
  583.       memset(adu->adu_Addr, 0, MAX_ADDR_BYTES);
  584.       adu->adu_Addr[0] = 255 - adu->adu_UnitNum;
  585.       ppunit = -1;
  586.       break;
  587.  
  588.     case WIRE_LOCALTALK:
  589.       /* Don't know much, but... */
  590.       hardwaretype  = S2WireType_LocalTalk;
  591.       addrfieldsize = 8;
  592.       maxtu = 256;
  593.       bps   = 128000L;        /* 128 kb/s */
  594.       mintu = 1;
  595.       /* Localnet address is got from unit number */
  596.       memset(address, 0, MAX_ADDR_BYTES);
  597.       address[0] = adu->adu_UnitNum;
  598.       ppunit = -1;
  599.       break;
  600.  
  601.       /* Amoknet parameters are all got with RaHi method */
  602.     case WIRE_AMOKNET:
  603.       /* Don't know much, but... */
  604.       hardwaretype  = S2WireType_AmokNet;
  605.       addrfieldsize = 8;
  606.       maxtu = 512;
  607.       bps   = 128000L;        /* 128 kb/s */
  608.       mintu = 1;
  609.       /* Amoknet address is got from unit number */
  610.       memset(address, 0, MAX_ADDR_BYTES);
  611.       address[0] = adu->adu_UnitNum;
  612.       break;
  613.  
  614.     case WIRE_PPP:
  615.       hardwaretype = S2WireType_PPP; goto serials;
  616.     case WIRE_SLIP:
  617.       hardwaretype = S2WireType_SLIP; goto serials;
  618.     case WIRE_CSLIP:
  619.       hardwaretype = S2WireType_CSLIP; 
  620.     serials: 
  621.       addrfieldsize = 32;
  622.       maxtu = 1006;
  623.       bps   = 9600L;        /* 9600 b/s */
  624.       mintu = 1;
  625.       /* SLIP address is set during config */
  626.       memset(address, 0, MAX_ADDR_BYTES);
  627.       break;
  628.     default:
  629.       if (errormessage)
  630.     *errormessage = ERR_WIRE;
  631.       error = 5;
  632.       goto free_and_exit;
  633.     }
  634.   }
  635.   if (args[CMD_MTU]) {
  636.     maxtu = *(ULONG *)args[CMD_MTU];
  637.   }
  638.  
  639.   if (args[CMD_MINTU]) {
  640.     mintu = *(ULONG *)args[CMD_MINTU];
  641.   }
  642.  
  643.   if (args[CMD_BPS]) {
  644.     bps = *(ULONG *)args[CMD_BPS];
  645.   }
  646.  
  647.   if (args[CMD_ADDR]) {
  648.     memset(address, 0, MAX_ADDR_BYTES);
  649.     if (!GetBitAddress(address, (UBYTE *)args[CMD_ADDR], addrfieldsize)) {
  650.       if (errormessage)
  651.     *errormessage = ERR_ADDRESS;
  652.       error = 7;
  653.       goto free_and_exit;
  654.     }
  655.   }
  656.  
  657.   if (args[CMD_DELAY]) {
  658.     delay = *(ULONG *)args[CMD_DELAY];
  659.     /* maximum delay is 0x800000 ms, that is fairly over an hour */
  660.     if (delay >= 0x800000)
  661.       delay = 0x7fffff;
  662.   }
  663.  
  664.   if (args[CMD_DEVIATION]) {
  665.     deviation = *(ULONG *)args[CMD_DEVIATION];
  666.   }
  667.  
  668.   if (args[CMD_ERRORS]) {
  669.     errors = *(ULONG *)args[CMD_ERRORS];
  670.     if (errors > ERRORS_MAX) {
  671.       error = 5;
  672.       *errormessage = ERR_VALUE;
  673.       goto free_and_exit;
  674.     }
  675.   }
  676.  
  677.   if (args[CMD_LOSS]) {
  678.     loss = *(ULONG *)args[CMD_LOSS];
  679.     if (loss > LOSS_MAX) {
  680.       error = 5;
  681.       *errormessage = ERR_VALUE;
  682.       goto free_and_exit;
  683.     }
  684.   }
  685.  
  686.   if (args[CMD_PPUNIT]) {
  687.     ppunit = *(ULONG *)args[CMD_PPUNIT];
  688.   }
  689.  
  690.   if (!virgin) {
  691.     LockUnit(adu);
  692.     /* 
  693.      * Changing the hardware type or reducing the MTU requires 
  694.      * that the unit is not currently open
  695.      */
  696.     if ((adu->adu_HardwareType != hardwaretype ||
  697.      adu->adu_MaxTU > maxtu) &&
  698.     adu->adu_Unit.unit_OpenCnt != 0 ) {
  699.       UnlockUnit(adu);
  700.       error = 5;
  701.       *errormessage = ERR_OPEN;
  702.       goto free_and_exit;
  703.     }
  704.   }
  705.  
  706.   adu->adu_HardwareType = hardwaretype;
  707.   adu->adu_AddrFieldSize = addrfieldsize;
  708.   adu->adu_PPUnit = ppunit;
  709.   adu->adu_MinTU = mintu;
  710.   adu->adu_BPS   = bps;
  711.   adu->adu_Delay = delay;
  712.   adu->adu_Deviation = deviation;
  713.   adu->adu_Errors = errors;
  714.   adu->adu_Loss  = loss;
  715.   memcpy(adu->adu_Addr, address, MAX_ADDR_BYTES);
  716.  
  717.   /*
  718.    * Enlarging the MTU requires offlining the device temporarily
  719.    */
  720.   if (!virgin && adu->adu_MaxTU < maxtu) {
  721.     DoOffline(adu);
  722.     adu->adu_MaxTU = maxtu;
  723.     DoOnline(adu);
  724.   } else {
  725.     adu->adu_MaxTU = maxtu;
  726.   }
  727.  
  728.   if (!virgin)
  729.     UnlockUnit(adu);
  730.  
  731.  free_and_exit:
  732.   if (rdargs) 
  733.     FreeArgs(rdargs);
  734.   return error;
  735. }
  736.  
  737. #ifdef AGREXX
  738. /*
  739.  * Parse Query Command
  740.  */
  741. static LONG
  742. ParseQuery(struct AgnetDevUnit *adu, 
  743.        struct RDArgs *rdargs,
  744.        STRPTR *errstr,
  745.        STRPTR *result)
  746. {
  747.   LONG errlevel = 0;
  748.   LONG args[CONFIG_ARGS] = {0};
  749.   char res[MAXQUERYLEN];
  750.   struct CSource csres = { NULL, sizeof(res), 0L };
  751.   BOOL all;
  752.   LONG i;
  753.  
  754.   csres.CS_Buffer = res;
  755.  
  756.   /* Parse the file or the line...*/
  757.   rdargs = ReadArgs(QUERY_TEMPLATE, args, rdargs);
  758.   if (errlevel = !rdargs) {
  759.     *errstr = ERR_SYNTAX;
  760.     return errlevel;
  761.   }
  762.  
  763.   all = args[CMD_ALL];
  764.   for (i = CMD_WIRE; i < CMD_ALL; i++) 
  765.     if (all || args[i]) {
  766.       if (csres.CS_CurChr != 0 && csres.CS_CurChr < csres.CS_Length) 
  767.     res[csres.CS_CurChr++] = ' ';
  768.       switch (query_titles[i].type) {
  769.       case nulong:
  770.     csprintf(&csres, "%s=%ld", query_titles[i].title, 
  771.                ULONG_AT(adu, query_titles[i].offset));
  772.     break;
  773.  
  774.       case wire:
  775.     {
  776.       int j; int type = ULONG_AT(adu, query_titles[i].offset);
  777.       for (j = 0; j < sizeof(wirenames)/sizeof(wirenames[0]) - 2; j++) 
  778.         if (wirenames[j].type == type) 
  779.           break;
  780.       csprintf(&csres, "%s=%s", query_titles[i].title, 
  781.           wirenames[j].name);
  782.     }
  783.     break;
  784.  
  785.       case address:
  786.     csprintf(&csres, "%s=%s", query_titles[i].title, 
  787.         SanaSprintf(AT_OFFSET(adu,query_titles[i].offset),
  788.                 adu->adu_AddrFieldSize + 7 >> 3));
  789.     break;
  790.       }
  791.     }
  792.  
  793.   *result = CreateArgstring(res, csres.CS_CurChr);
  794.   if (!*result) {
  795.     *errstr = ERR_MEMORY;
  796.     return 40;
  797.   }
  798.   return errlevel;
  799. }
  800.  
  801. #endif /* AGREXX */
  802.  
  803. /*
  804.  * Read hexadecimal address string into array.
  805.  *
  806.  * UBYTE *addr     = address array
  807.  * UBYTE *string   = hexadecimal address string, 
  808.  *                   each byte sparated by colon (":")
  809.  * LONG   bitsize  = address length in bits
  810.  *
  811.  * Return true if no errors.
  812.  * If there is error, may trash the address.
  813.  */
  814. static BOOL 
  815. GetBitAddress(UBYTE *addr, UBYTE *string, LONG bitsize)
  816. {
  817.   LONG bitsperbyte; UWORD next; UWORD chars;
  818.   UBYTE c;
  819.  
  820.   memset(addr, 0, (bitsize + 7) >> 3);
  821.  
  822.   while (bitsize > 0) {
  823.     bitsperbyte = bitsize < 8 ? bitsize : 8;
  824.     chars = next = 0;
  825.     while ((c = *string - '0') <= 9 
  826.       || (c = c - 'A' + '0' + 10) >= 9 && c < 16  /*ABCDEF*/
  827.       || (c = c - 'a' + 'A') >= 9 && c < 16) /*abcdef*/ {
  828.       chars++; string++;
  829.       next = (next << 4) + c;
  830.       if (next >= 1 << bitsperbyte)
  831.     return FALSE;
  832.     }
  833.     if (!chars)
  834.       return FALSE;
  835.  
  836.     *addr++ = next << (8 - bitsperbyte);
  837.     bitsize -= bitsperbyte;
  838.     if (*string != ':')
  839.       break;
  840.     string++;
  841.   }
  842.   if (bitsize || *string) return FALSE;
  843.   return TRUE;
  844. }
  845.  
  846. /*
  847.  * Print Hardware Address
  848.  */
  849. static char *
  850. SanaSprintf(register char *ap, int len)
  851. {
  852.   const char *digits = "0123456789ABCDEF";
  853.   register i;
  854.   static char addrbuf[17*3];
  855.   register unsigned char *cp = addrbuf;
  856.  
  857.   for (i = 0; i < len; ) {
  858.     *cp++ = digits[*ap >> 4];
  859.     *cp++ = digits[*ap++ & 0xf];
  860.     i++;
  861.     if (i < len) 
  862.       *cp++ = ':';
  863.   }
  864.   *cp = 0;
  865.   return (addrbuf);
  866. }
  867.  
  868. void ASM stuffchar(REG(d0) char ch, REG(a3) struct CSource * sc)
  869. {
  870.   if (sc->CS_CurChr < sc->CS_Length 
  871.       && (sc->CS_Buffer[sc->CS_CurChr] = ch))
  872.     sc->CS_CurChr++;
  873. }
  874.  
  875. static ULONG
  876. csprintf(struct CSource *buf, const char *fmt, ...)
  877. {
  878.   ULONG start = buf->CS_CurChr;
  879.   va_list ap;
  880.  
  881.   va_start(ap, fmt);
  882.   RawDoFmt((STRPTR)fmt, ap, stuffchar, buf);
  883.   va_end(ap);
  884.  
  885.   buf->CS_Buffer[buf->CS_CurChr] = '\0';
  886.   return buf->CS_CurChr - start;
  887. }
  888.  
  889.